﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web.UI;
using AqueleAjax.UI.Controls;

namespace AqueleAjax.UI
{
    /// <summary>
    /// Classe responsável em gerenciar os scripts gerados e enviados ao cliente. Esta classe não pode ser herdada.
    /// </summary>
    public sealed class ClientScript
    {
        #region Constantes
        /// <summary>
        /// Nome da função JavaScript que captura o resultado da chamada assíncrona.
        /// </summary>
        internal const string ResultCallbackFunction = "___aqueleAjax.ResultCallback";
        
        /// <summary>
        /// Nome da função JavaScript que captura o erro gerado na chamada assíncrona.
        /// </summary>
        internal const string ErrorCallbackFunction = "___aqueleAjax.ErrorCallback";
        
        #endregion

        #region Propriedades

        private AjaxMainControl _currentMainControl;
        /// <summary>
        /// Instância do AjaxMainControl relacionado ao ClientScript.
        /// </summary>
        public AjaxMainControl CurrentMainControl
        {
            get { return this._currentMainControl; }
            private set { this._currentMainControl = value; }
        }

        private StringDictionary _scripts;

        /// <summary>
        /// Coleção de scripts que deverão ser enviados ao cliente.
        /// </summary>
        internal StringDictionary Scripts
        {
            get
            {
                if (this._scripts == null)
                {
                    this._scripts = new StringDictionary();
                }

                return this._scripts;
            }
        }
        #endregion

        #region Construtores
        /// <summary>
        /// Instância o ClientScript configurando o AjaxMainControl relacionado.
        /// </summary>
        /// <param name="mainControl">Instância do AjaxMainControl que contém o ClientScript.</param>
        public ClientScript(AjaxMainControl mainControl)
        {
            if (mainControl == null) throw new ArgumentNullException("mainControl");

            this.CurrentMainControl = mainControl;
            this.RegisterBasicScriptBlock();
        }
        #endregion

        #region Métodos públicos
        /// <summary>
        /// Registra um script para ser enviado ao cliente.
        /// </summary>
        /// <param name="key">Chave que identifica o script. Esta chave não será duplicada.</param>
        /// <param name="script">Script que será enviado ao cliente.</param>
        public void RegisterScript(string key, string script)
        {
            if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
            if (string.IsNullOrEmpty(script)) throw new ArgumentNullException("script");

            if (!this.IsRegisteredScript(key))
            {
                this.Scripts.Add(key, script);
            }
        }

        /// <summary>
        /// Verifica se já existe um script registrado com a chave.
        /// </summary>
        /// <param name="key">Chave que será verificada.</param>
        /// <returns>Retorna TRUE se a chave estiver registrada.</returns>
        public bool IsRegisteredScript(string key)
        {
            if (string.IsNullOrEmpty(key)) return false;

            return this.Scripts.ContainsKey(key);
        }
        #endregion

        #region Métodos privados
        /// <summary>
        /// Registra o script básico para funcionamento do framework.
        /// </summary>
        private void RegisterBasicScriptBlock()
        {
            this.RegisterUtilFunctionsScriptBlock();
            this.RegisterAqueleAjaxCoreScriptBlock();
            this.RegisterDeclarationsScriptBlock();            
        }

        private void RegisterAqueleAjaxCoreScriptBlock()
        {
            this.RegisterBasicScriptBlock(ResourceManager.AqueleAjaxCore);
        }

        private void RegisterDeclarationsScriptBlock()
        {
            this.RegisterBasicScriptBlock(ResourceManager.Declarations);
        }

        private void RegisterUtilFunctionsScriptBlock()
        {
            this.RegisterBasicScriptBlock(ResourceManager.UtilFunctions);
        }

        private void RegisterBasicScriptBlock(string scriptName)
        {
            if (this.CurrentMainControl.Page.ClientScript.IsClientScriptIncludeRegistered(scriptName)) return;

            string script = this.CurrentMainControl.Page.ClientScript.GetWebResourceUrl(
                this.CurrentMainControl.GetType(),
                scriptName
                );

            this.CurrentMainControl.Page.ClientScript.RegisterClientScriptInclude(
               this.CurrentMainControl.Page.GetType(),
               scriptName,
               script
               );
        }
        #endregion
    }
}
